user error when no space support on HS

remove buggy separators on add room; design update
This commit is contained in:
Valere 2021-05-11 17:34:26 +02:00
parent 91d8ee2a81
commit eb9fadaebf
11 changed files with 201 additions and 47 deletions

View File

@ -0,0 +1,85 @@
/*
* Copyright 2019 New Vector Ltd
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package im.vector.app.core.ui.list
import android.content.res.ColorStateList
import android.view.Gravity
import android.widget.ImageView
import android.widget.TextView
import androidx.annotation.DrawableRes
import androidx.core.widget.ImageViewCompat
import com.airbnb.epoxy.EpoxyAttribute
import com.airbnb.epoxy.EpoxyModelClass
import im.vector.app.R
import im.vector.app.core.epoxy.VectorEpoxyHolder
import im.vector.app.core.epoxy.VectorEpoxyModel
import im.vector.app.core.extensions.setTextOrHide
import im.vector.app.features.themes.ThemeUtils
/**
* A generic list item.
* Displays an item with a title, and optional description.
* Can display an accessory on the right, that can be an image or an indeterminate progress.
* If provided with an action, will display a button at the bottom of the list item.
*/
@EpoxyModelClass(layout = R.layout.item_generic_pill_footer)
abstract class GenericPillItem : VectorEpoxyModel<GenericPillItem.Holder>() {
@EpoxyAttribute
var text: CharSequence? = null
@EpoxyAttribute
var style: ItemStyle = ItemStyle.NORMAL_TEXT
@EpoxyAttribute
var itemClickAction: GenericItem.Action? = null
@EpoxyAttribute
var centered: Boolean = false
@EpoxyAttribute
@DrawableRes
var imageRes: Int? = null
@EpoxyAttribute
var tintIcon: Boolean = true
override fun bind(holder: Holder) {
super.bind(holder)
holder.textView.setTextOrHide(text)
holder.textView.typeface = style.toTypeFace()
holder.textView.textSize = style.toTextSize()
holder.textView.gravity = if (centered) Gravity.CENTER_HORIZONTAL else Gravity.START
imageRes?.let { holder.imageView.setImageResource(it) }
if (tintIcon) {
val iconTintColor = ThemeUtils.getColor(holder.view.context, R.attr.riotx_text_secondary)
ImageViewCompat.setImageTintList(holder.imageView, ColorStateList.valueOf(iconTintColor))
} else {
ImageViewCompat.setImageTintList(holder.imageView, null)
}
holder.view.setOnClickListener {
itemClickAction?.perform?.run()
}
}
class Holder : VectorEpoxyHolder() {
val imageView by bind<ImageView>(R.id.itemGenericPillImage)
val textView by bind<TextView>(R.id.itemGenericPillText)
}
}

View File

@ -18,13 +18,21 @@ package im.vector.app.features.spaces.explore
import android.view.View import android.view.View
import com.airbnb.epoxy.TypedEpoxyController import com.airbnb.epoxy.TypedEpoxyController
import com.airbnb.mvrx.Fail
import com.airbnb.mvrx.Incomplete import com.airbnb.mvrx.Incomplete
import im.vector.app.R import im.vector.app.R
import im.vector.app.core.epoxy.errorWithRetryItem
import im.vector.app.core.epoxy.loadingItem import im.vector.app.core.epoxy.loadingItem
import im.vector.app.core.error.ErrorFormatter
import im.vector.app.core.resources.ColorProvider
import im.vector.app.core.resources.StringProvider import im.vector.app.core.resources.StringProvider
import im.vector.app.core.ui.list.genericFooterItem import im.vector.app.core.ui.list.genericFooterItem
import im.vector.app.core.ui.list.genericPillItem
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
import im.vector.app.features.home.room.list.spaceChildInfoItem import im.vector.app.features.home.room.list.spaceChildInfoItem
import me.gujun.android.span.span
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.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.MatrixItem import org.matrix.android.sdk.api.util.MatrixItem
@ -32,13 +40,16 @@ import javax.inject.Inject
class SpaceDirectoryController @Inject constructor( class SpaceDirectoryController @Inject constructor(
private val avatarRenderer: AvatarRenderer, private val avatarRenderer: AvatarRenderer,
private val stringProvider: StringProvider private val stringProvider: StringProvider,
private val colorProvider: ColorProvider,
private val errorFormatter: ErrorFormatter
) : TypedEpoxyController<SpaceDirectoryState>() { ) : TypedEpoxyController<SpaceDirectoryState>() {
interface InteractionListener { interface InteractionListener {
fun onButtonClick(spaceChildInfo: SpaceChildInfo) fun onButtonClick(spaceChildInfo: SpaceChildInfo)
fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo) fun onSpaceChildClick(spaceChildInfo: SpaceChildInfo)
fun onRoomClick(spaceChildInfo: SpaceChildInfo) fun onRoomClick(spaceChildInfo: SpaceChildInfo)
fun retry()
} }
var listener: InteractionListener? = null var listener: InteractionListener? = null
@ -50,6 +61,33 @@ class SpaceDirectoryController @Inject constructor(
loadingItem { loadingItem {
id("loading") id("loading")
} }
} else if (results is Fail) {
val failure = results.error
if (failure is Failure.ServerError && failure.error.code == M_UNRECOGNIZED) {
genericPillItem {
id("HS no Support")
imageRes(R.drawable.error)
tintIcon(false)
text(
span {
span(stringProvider.getString(R.string.spaces_no_server_support_title)) {
textStyle = "bold"
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_primary)
}
+"\n\n"
span(stringProvider.getString(R.string.spaces_no_server_support_description)) {
textColor = colorProvider.getColorFromAttribute(R.attr.riotx_text_secondary)
}
}
)
}
} else {
errorWithRetryItem {
id("api_err")
text(errorFormatter.toHumanReadable(failure))
listener { listener?.retry() }
}
}
} else { } else {
val flattenChildInfo = results?.invoke() val flattenChildInfo = results?.invoke()
?.filter { ?.filter {

View File

@ -94,6 +94,9 @@ class SpaceDirectoryFragment @Inject constructor(
return true return true
} }
override fun retry() {
viewModel.handle(SpaceDirectoryViewAction.Retry)
}
// override fun navigateToRoom(roomId: String) { // override fun navigateToRoom(roomId: String) {
// viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId)) // viewModel.handle(SpaceDirectoryViewAction.NavigateToRoom(roomId))
// } // }

View File

@ -25,4 +25,5 @@ sealed class SpaceDirectoryViewAction : VectorViewModelAction {
data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction() data class ShowDetails(val spaceChildInfo: SpaceChildInfo) : SpaceDirectoryViewAction()
data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction() data class NavigateToRoom(val roomId: String) : SpaceDirectoryViewAction()
object HandleBack : SpaceDirectoryViewAction() object HandleBack : SpaceDirectoryViewAction()
object Retry : SpaceDirectoryViewAction()
} }

View File

@ -39,7 +39,7 @@ import org.matrix.android.sdk.rx.rx
import timber.log.Timber import timber.log.Timber
class SpaceDirectoryViewModel @AssistedInject constructor( class SpaceDirectoryViewModel @AssistedInject constructor(
@Assisted initialState: SpaceDirectoryState, @Assisted val initialState: SpaceDirectoryState,
private val session: Session private val session: Session
) : VectorViewModel<SpaceDirectoryState, SpaceDirectoryViewAction, SpaceDirectoryViewEvents>(initialState) { ) : VectorViewModel<SpaceDirectoryState, SpaceDirectoryViewAction, SpaceDirectoryViewEvents>(initialState) {
@ -63,11 +63,21 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
val spaceSum = session.getRoomSummary(initialState.spaceId) val spaceSum = session.getRoomSummary(initialState.spaceId)
setState { setState {
copy( copy(
childList = spaceSum?.spaceChildren ?: emptyList(), childList = spaceSum?.spaceChildren ?: emptyList()
spaceSummaryApiResult = Loading()
) )
} }
refreshFromApi()
observeJoinedRooms()
observeMembershipChanges()
}
private fun refreshFromApi() {
setState {
copy(
spaceSummaryApiResult = Loading()
)
}
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch(Dispatchers.IO) {
try { try {
val query = session.spaceService().querySpaceChildren(initialState.spaceId) val query = session.spaceService().querySpaceChildren(initialState.spaceId)
@ -84,8 +94,6 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
} }
} }
} }
observeJoinedRooms()
observeMembershipChanges()
} }
private fun observeJoinedRooms() { private fun observeJoinedRooms() {
@ -146,6 +154,9 @@ class SpaceDirectoryViewModel @AssistedInject constructor(
_viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it)) _viewEvents.post(SpaceDirectoryViewEvents.NavigateToMxToBottomSheet(it))
} }
} }
SpaceDirectoryViewAction.Retry -> {
refreshFromApi()
}
} }
} }

View File

@ -19,6 +19,8 @@ package im.vector.app.features.spaces.manage
import androidx.recyclerview.widget.DiffUtil import androidx.recyclerview.widget.DiffUtil
import com.airbnb.epoxy.EpoxyModel import com.airbnb.epoxy.EpoxyModel
import com.airbnb.epoxy.paging.PagedListEpoxyController import com.airbnb.epoxy.paging.PagedListEpoxyController
import im.vector.app.R
import im.vector.app.core.ui.list.GenericPillItem_
import im.vector.app.core.utils.DebouncedClickListener import im.vector.app.core.utils.DebouncedClickListener
import im.vector.app.core.utils.createUIHandler import im.vector.app.core.utils.createUIHandler
import im.vector.app.features.home.AvatarRenderer import im.vector.app.features.home.AvatarRenderer
@ -56,6 +58,8 @@ class AddRoomListController @Inject constructor(
var listener: Listener? = null var listener: Listener? = null
var ignoreRooms: List<String>? = null var ignoreRooms: List<String>? = null
var subHeaderText: CharSequence? = null
var initialLoadOccurred = false var initialLoadOccurred = false
fun boundaryChange(boundary: ResultBoundaries) { fun boundaryChange(boundary: ResultBoundaries) {
@ -100,6 +104,15 @@ class AddRoomListController @Inject constructor(
expanded(true) expanded(true)
} }
) )
if (subHeaderText != null) {
add(
GenericPillItem_().apply {
id("sub_header")
text(subHeaderText)
imageRes(R.drawable.ic_info)
}
)
}
} }
super.addModels(filteredModel) super.addModels(filteredModel)
if (!initialLoadOccurred) { if (!initialLoadOccurred) {

View File

@ -16,9 +16,6 @@
package im.vector.app.features.spaces.manage package im.vector.app.features.spaces.manage
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
import android.view.Menu import android.view.Menu
@ -26,12 +23,8 @@ import android.view.MenuItem
import android.view.View import android.view.View
import android.view.ViewGroup import android.view.ViewGroup
import androidx.appcompat.app.AlertDialog import androidx.appcompat.app.AlertDialog
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.ConcatAdapter import androidx.recyclerview.widget.ConcatAdapter
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.airbnb.epoxy.EpoxyViewHolder
import com.airbnb.mvrx.Loading import com.airbnb.mvrx.Loading
import com.airbnb.mvrx.activityViewModel import com.airbnb.mvrx.activityViewModel
import com.airbnb.mvrx.fragmentViewModel import com.airbnb.mvrx.fragmentViewModel
@ -41,7 +34,6 @@ import im.vector.app.core.extensions.cleanup
import im.vector.app.core.platform.OnBackPressed import im.vector.app.core.platform.OnBackPressed
import im.vector.app.core.platform.VectorBaseFragment import im.vector.app.core.platform.VectorBaseFragment
import im.vector.app.databinding.FragmentSpaceAddRoomsBinding import im.vector.app.databinding.FragmentSpaceAddRoomsBinding
import im.vector.app.features.home.room.list.RoomCategoryItem_
import io.reactivex.rxkotlin.subscribeBy import io.reactivex.rxkotlin.subscribeBy
import org.matrix.android.sdk.api.session.room.model.RoomSummary import org.matrix.android.sdk.api.session.room.model.RoomSummary
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
@ -88,6 +80,7 @@ class SpaceAddRoomFragment @Inject constructor(
} }
.disposeOnDestroyView() .disposeOnDestroyView()
spaceEpoxyController.subHeaderText = getString(R.string.spaces_feeling_experimental_subspace)
viewModel.selectionListLiveData.observe(viewLifecycleOwner) { viewModel.selectionListLiveData.observe(viewLifecycleOwner) {
spaceEpoxyController.selectedItems = it spaceEpoxyController.selectedItems = it
roomEpoxyController.selectedItems = it roomEpoxyController.selectedItems = it
@ -183,36 +176,6 @@ class SpaceAddRoomFragment @Inject constructor(
} }
views.roomList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false) views.roomList.layoutManager = LinearLayoutManager(context, LinearLayoutManager.VERTICAL, false)
views.roomList.addItemDecoration(
object : DividerItemDecoration(context, VERTICAL) {
val decorationDrawable = ContextCompat.getDrawable(requireContext(), R.drawable.divider_horizontal)
override fun getDrawable(): Drawable? {
return decorationDrawable
}
override fun getItemOffsets(outRect: Rect, view: View, parent: RecyclerView, state: RecyclerView.State) {
val position = parent.getChildAdapterPosition(view)
val vh = parent.findViewHolderForAdapterPosition(position)
val nextIsSectionOrFinal = parent.findViewHolderForAdapterPosition(position + 1)?.let {
(it as? EpoxyViewHolder)?.model is RoomCategoryItem_
} ?: true
if (vh == null
|| (vh as? EpoxyViewHolder)?.model is RoomCategoryItem_
|| nextIsSectionOrFinal
) {
outRect.setEmpty()
} else {
super.getItemOffsets(outRect, view, parent, state)
}
}
override fun onDraw(c: Canvas, parent: RecyclerView, state: RecyclerView.State) {
super.onDraw(c, parent, state)
}
}
)
views.roomList.setHasFixedSize(true) views.roomList.setHasFixedSize(true)
concatAdapter.addAdapter(roomEpoxyController.adapter) concatAdapter.addAdapter(roomEpoxyController.adapter)

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="16dp"
android:height="16dp"
android:viewportWidth="16"
android:viewportHeight="16">
<path
android:pathData="M14.6666,7.9999C14.6666,11.6818 11.6818,14.6666 7.9999,14.6666C4.318,14.6666 1.3333,11.6818 1.3333,7.9999C1.3333,4.318 4.318,1.3333 7.9999,1.3333C11.6818,1.3333 14.6666,4.318 14.6666,7.9999ZM6.3333,7.9999C6.3333,8.4353 6.6115,8.8057 6.9999,8.943V10.9999C6.9999,11.5522 7.4476,11.9999 7.9999,11.9999H8.9999C9.5522,11.9999 9.9999,11.5522 9.9999,10.9999C9.9999,10.4476 9.5522,9.9999 8.9999,9.9999V7.9999C8.9999,7.4476 8.5522,6.9999 7.9999,6.9999H7.3333C6.781,6.9999 6.3333,7.4476 6.3333,7.9999ZM7.9999,6.6666C8.5522,6.6666 8.9999,6.2189 8.9999,5.6666C8.9999,5.1143 8.5522,4.6666 7.9999,4.6666C7.4476,4.6666 6.9999,5.1143 6.9999,5.6666C6.9999,6.2189 7.4476,6.6666 7.9999,6.6666Z"
android:fillColor="#737D8C"
android:fillType="evenOdd"/>
</vector>

View File

@ -10,7 +10,7 @@
android:id="@+id/roomList" android:id="@+id/roomList"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="?riotx_header_panel_background" android:background="?riotx_background"
android:overScrollMode="always" android:overScrollMode="always"
app:layout_behavior="@string/appbar_scrolling_view_behavior" app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:listitem="@layout/item_room_to_add_in_space" /> tools:listitem="@layout/item_room_to_add_in_space" />

View File

@ -0,0 +1,27 @@
<?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:layout_margin="16dp"
android:background="@drawable/rounded_rect_shape_8"
android:backgroundTint="?riotx_reaction_background_off"
android:orientation="horizontal"
android:padding="16dp">
<ImageView
android:id="@+id/itemGenericPillImage"
android:layout_width="20dp"
android:layout_height="20dp"
android:src="@drawable/ic_info"
android:tint="?riotx_text_secondary" />
<TextView
android:id="@+id/itemGenericPillText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:gravity="start"
tools:text="@tools:sample/lorem" />
</LinearLayout>

View File

@ -3365,4 +3365,7 @@
<string name="labs_space_show_orphan_in_home">Experimental Space - Only show orphans in Home</string> <string name="labs_space_show_orphan_in_home">Experimental Space - Only show orphans in Home</string>
<string name="spaces_feeling_experimental_subspace">Feeling experimental?\nYou can add existing spaces to a space.</string>
<string name="spaces_no_server_support_title">It looks like your homeserver does not support Spaces yet</string>
<string name="spaces_no_server_support_description">Please contact your homserver admin for further information</string>
</resources> </resources>